import React, { useEffect, useRef } from 'react';

const pdf = encodeURIComponent('/JavaScript.pdf');

// 这里我扩展了一下 pdf.js 的 window 对象，因为我需要使用到里面的属性
type IframeWindow = {
    PDFViewerApplication: {
        eventBus: {
            dispatch: (type: string, data: any) => void;
        };
        pagesCount: number;
    };
} & Window;

export default function Page() {
    const iframeRef = useRef<HTMLIFrameElement | null>(null);

    useEffect(() => {
        const highlightPDF = setInterval(() => {
            const iframe = iframeRef.current!;
            // 检查 iframe 是否加载完成，这里我是使用 iframe 的 windows 上是否已经有了 pagesCount 属性来判断
            const iframeWindow = iframe.contentWindow as IframeWindow;
            const pagesCount = iframeWindow?.PDFViewerApplication?.pagesCount;
            // console.log('PDF 总页数', pagesCount);
            if (!pagesCount) return;

            // 获取 iframe 的 document
            const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
            const pages = iframeDoc?.querySelectorAll('.page');
            // 这里之所以使用 setInterval，是因为 pdf.js 是动态加载页面内容的
            // .page 元素里的内容会动态增删，所以如果只执行一次，后面的页面都会没有高亮效果
            const keywords0 = [
                '如果购买者有侵权行为',
                '对该用户实施包括但不限于关闭该',
                '帐号等维权措施，并可能追究法律',
                '责任。',
            ];
            const pattern = /\[\(\)（）\[\]\|\/-——]/g;
            const highlightDom = (dom: HTMLElement) => {
                // 取出 .page 元素中的 .textLayer 元素，这个元素就是 pdf 文件中的文字内容
                const textLayer = dom.querySelector('.textLayer');
                if (!textLayer) return;

                // 这里我使用了正则去除掉所有的特殊符号，因为中英文符号可能导致不匹配
                for (const node of [...textLayer.children]) {
                    if (node.textContent) {
                        const result = keywords0.filter((keyword) =>
                            node.textContent!.replace(pattern, '').includes(keyword.replace(pattern, '')),
                        );
                        node.style.backgroundColor = !result.length ? 'transparent' : 'red';
                    }
                }
            };
            if (!pages) return;

            // 对后台拿到的关键词数组进行去重，如果没有关键词的就不进行遍历操作了
            const keywords = [...new Set(keywords0)];
            if ((keywords.length === 1 && !keywords[0]) || !keywords.length) return;

            // 遍历 .page 元素进行高亮
            for (let i = 0; i < pages.length; i += 1) {
                const currentPage = pages[i];
                if (currentPage) {
                    highlightDom(currentPage);
                }
            }
        }, 1500);
    }, []);

    const onSearch = (e) => {
        // 获取 iframe 的 window
        const iframe = iframeRef.current;
        const iframeWindow = iframe?.contentWindow as IframeWindow | null;
        if (!iframeWindow) return;

        // 获取 iframe 中的搜索 input
        const searchInput = iframeWindow.document.querySelector('#findInput') as HTMLInputElement | null;

        // 定义搜索方法
        const searchKeyword = (keyword: string) => {
            if (!iframeWindow || !searchInput) return;
            // 将关键词赋值给 input
            searchInput!.value = keyword;
            // 调用 pdf.js 的搜索方法
            iframeWindow.PDFViewerApplication.eventBus.dispatch('find', {
                type: '',
                query: keyword,
                highlightAll: true,
            });
        };

        searchKeyword(e.target.innerText);
    };

    return (
        <main className=' w-full h-screen flex'>
            <iframe
                id='iframe'
                className=' w-full h-full'
                ref={iframeRef}
                title='pdf预览'
                src={`/pdfjs-dist/web/viewer.html?file=${pdf}`}
            />
            <ul>
                <li>
                    <button type='button' onClick={onSearch}>
                        要定义浮点值，数值中必须包含小数点，而且小数点后面必须至少有一个数字。虽然小数点前面不是必须有整数，但推荐加上。下面是几个例子
                    </button>
                </li>
                <li>
                    <button type='button' onClick={onSearch}>
                        虽然超出有限数值范围的计算并不多见，但总归还是有可能的。因此在计算非常大或非常小的数值时，有必要监测一下计算结果是否超出范围
                    </button>
                </li>
            </ul>
        </main>
    );
}
